using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace Ndo.FenCi
{
    public class IntRandomStModel<TKey> : IEnumerable<KeyValuePair<TKey, int>>
    {
        public IntRandomStModel()
            : this(int.MaxValue >> 1)
        {
        }

        public IntRandomStModel(int defaultValue)
        {
            this.defaultValue = defaultValue;   
        }

        private int defaultValue;
        public int DefaultValue
        {
            get
            {
                return this.defaultValue;
            }
        }
        private class Data
        {
            public Data(int v)
            {
                this.value = v;
            }
            public int value;
        }
        private Dictionary<TKey, Data> map = new Dictionary<TKey, Data>();
        private Random rand = new Random();
        public virtual void Impress(TKey key)
        {
            Data a;
            bool b;
            lock(this)
            {
                if (!map.TryGetValue(key, out a))
                {
                    a = new Data(defaultValue);
                    map[key] = a;
                    return;
                }
            }
            int r = rand.Next();
            lock(a)
            {
                if (b = r > a.value)
                {
                    a.value++;
                }
            }
            if(b)
            {
                OnValueChanged(key);
            }
        }
        public virtual void Depress(TKey key)
        {
            Data a;
            bool b;
            lock (this)
            {
                if (!map.TryGetValue(key, out a))
                {
                    a = new Data(defaultValue);
                    map[key] = a;
                    return;
                }
            }
            int r = rand.Next();
            lock (a)
            {
                if (b = r < a.value)
                {
                    a.value--;
                }
            }
            if (b)
            {
                OnValueChanged(key);
            }
        }
        public virtual void OnValueChanged(TKey key)
        {}
        public virtual int this[TKey key]
        {
            get
            {
                Data a;
                lock (this)
                {
                    if (map.TryGetValue(key, out a))
                    {
                        return a.value;
                    }
                }
                return -1;
            }
            set
            {
                Data a;
                lock (this)
                {
                    if (!map.TryGetValue(key, out a))
                    {
                        a = new Data(value);
                        map[key] = a;
                        return;
                    }
                    a.value = value;
                }
            }
        }

        public bool ContainsKey(TKey key)
        {
            lock(this)
            {
                return map.ContainsKey(key);
            }
        }

        public IEnumerator<KeyValuePair<TKey, int>> GetEnumerator()
        {
            foreach (KeyValuePair<TKey, Data> pair in map)
            {
                yield return new KeyValuePair<TKey, int>(pair.Key, pair.Value.value);
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            foreach (KeyValuePair<TKey, Data> pair in map)
            {
                yield return new KeyValuePair<TKey, int>(pair.Key, pair.Value.value);
            }
        }
    }
}
